import MathEx from '../../../Core/Math/MathEx';
import GameMgr from '../../Logic/GameMgr';
import { INVALID_VALUE } from './../../../Core/CoreDefine';
import { PART_PROPTS } from './../../Common/Define';
import { JXBattleCb } from './JXBattleCb';
import { ERR_SKILL_EFFECT, JXBattleEvt, JXBtlAns_PressModel, JXBtlArrIx, JXBtlBEM, JXBtlBEMT, JXBtlBER, JXBtlCamp, JxBtlCollisionType, JXBtlPs, JXBtlSAirCEM, JXBtlSAirT, JXBtlSAirTR, JXBtlSRC, JXBtlSSM, JXBtlST, JXBtl_Race } from './JXBattleDefine';
import JXBtlMgr from './JXBattleManager';
import { JXBattleEntity, JXBattleTeamEntiry } from './JXBattleRole';
import { JXBattleUtility, JXRoundTimer } from './JXBattleUtility';


const BUFF_FLAG = JXBtlPs.B.FLAG;
/** 效果，效果不是指BUFF,而是指BUFF和技能的原型。 */
export class JXBattleEffect {
	/** effect-Id */
	public nBufId: number;
	/** 效果作用概率 */
	public nBufRate: number;
	/** 效果准备时间 */
	public nBufPrepare: number;
	/** 效果持续时间 */
	public nBufDuration: number;
	/** 本技能效果中的序号 */
	public nIndex: number;
	/** 计算参数 */
	public affect: any[];
	/** 来自于技能 */
	public skill: JXBattleSkill;
	/** 持续信息 */
	public continues: number[] /** [number, number] */;
	/** 衰减 */
	public decay: number;
	/** 绑定的效果组 */
	public groups: JXBattleEffect[];
	/** 绑定的效果组的父效果 */
	public groupRoot: JXBattleEffect;
	public targets: JXBattleEntity[];


	/** 获取效果的优先级 */
	public get priority(): number {
		if (!this.skill) return null;
		return this.skill.priority;
	}



	constructor(nIndex: number, nId: number, nDuration: number) {
		this.nIndex = nIndex;
		this.nBufId = nId;
		this.nBufRate = 1;
		this.nBufPrepare = 0;
		this.nBufDuration = nDuration;
	}

	/** 添加效果到效果组中 */
	public addInGroup(effect: JXBattleEffect) {
		if (!this.groups) this.groups = [];
		this.groups.push(effect);
		effect.groups = this.groups;
		effect.groupRoot = this;
		effect.bindContinue(this.continues);
	}


	/** 绑定技能 */
	public bindTarget(skill: JXBattleSkill) {
		this.skill = skill;
		return this;
	}

	/** 绑定计算公式 */
	public bindAffect(affect: any[]) {
		this.affect = affect;
		return this;
	}

	/**绑定持续效果 */
	public bindContinue(nContinue: number[]) {
		this.continues = nContinue;
		return this;
	}

	/** 子效果生效 */
	public activeChild(target: JXBattleEntity, rootBuff: JXBattleBuff, ansTargets: JXAnsSkillEffect[]): JXBattleBuff {
		let buff = new JXBattleBuff(this);
		let ret = buff.bindTarget(target);
		if (ret && rootBuff) {
			rootBuff.addInGroup(buff);
		}
		ansTargets.push({ index: this.nIndex, effectId: this.nBufId, target: target.id, buffInsId: buff.uuid })
		return ret;
	}

	public bindAtkTargets(targets: JXBattleEntity[]) {
		this.targets = targets;
	}

	/** 生效 */
	public active() {
		let ansTargets: JXAnsSkillEffect[] = [];
		let targets = this.targets;
		if (!targets || targets.length == 0) return;
		for (let i = 0; i < targets.length; i++) {
			let buff = new JXBattleBuff(this);
			let ret = buff.bindTarget(targets[i]);
			// 如果是存在组效果，则进行组激活
			if (this.groups && this.groups.indexOf(this) == JXBtlPs.Invalid) {
				for (let j = 0; j < this.groups.length; j++) {
					let ret1 = this.groups[j].activeChild(targets[i], ret, ansTargets);
					ret = ret || ret1;
				}
			}
			// 缓存BUFF
			let buffs: JXBattleBuff[] = [];
			if (ret) {
				if (ret == buff) {
					buffs.push(buff);
					if (buff.groups && buff.groups.length > 0) {
						buffs.push(...buff.groups);
					}
				}
				else {
					buffs.push(ret);
					if (ret.groups && ret.groups.length > 0) {
						buffs.push(...ret.groups);
					}
				}
			}
			for (let i = 0; i < buffs.length; i++) {
				buffs[i].onCreate();
			}
			ansTargets.splice(0, 0, { index: this.nIndex, effectId: this.nBufId, target: targets[i].id, buffInsId: buff.uuid });
		}
		return ansTargets;
	}
}

export class JXBattleSkill {
	public skillId: number;
	public skillIdx: number;
	public skillRes: SSkillDataRaw;
	public our: JXBattleEntity;
	public state: JXBtlSSM = JXBtlSSM.Idle;
	public effects: JXBattleEffect[];


	/** 效果作用目标类型 */
	public nAirCamp: number;
	/** 目标类型选择 */
	public nAirType: number;
	/** 作用范围 */
	public nAirRange: number;
	/** 目标选中概率 */
	public nAirNum: number;

	/** 获取技能优先级 */
	public get priority() {
		return JXBtlPs.S.PRI[this.skillRes.type];
	}

	constructor(skillId: number, skillIdx: number) {
		this.effects = [];
		this.skillId = skillId;
		this.skillRes = JXBattleCb.getSkillData(skillId);
		this.skillIdx = skillIdx;
		let affects: number[][] = this.skillRes.affect;
		this.bindCondition(...this.skillRes.position as [number, number, number, number])
		for (let i = 0; i < this.skillRes.skillEffect.length; i++) {
			let effectTpl = this.skillRes.skillEffect[i] as [number, number];
			let affect = affects[i];
			let effect = new JXBattleEffect(i, ...effectTpl).bindTarget(this);
			effect.bindAffect(affect);
			let positon: number[] = this.skillRes.position;
			if (!!positon && positon.length > 0) {
				//所有技能立即生效不存在终端
				effect.bindContinue([1, this.skillRes.condition[JXBtlPs.S.PCDT.Rate]])
				this.effects.push(effect);
			} else {
				let lastEffect = this.effects[this.effects.length - 1];
				if (!lastEffect) {
					throw new Error(ERR_SKILL_EFFECT);
				}
				lastEffect.addInGroup(effect);
			}
		}

	}

	/** 绑定目标判定机制 */
	public bindCondition(nAirCamp: number, nAirType: number, nAirRange: number, nAirNum: number) {
		this.nAirCamp = nAirCamp;
		this.nAirType = nAirType;
		this.nAirRange = nAirRange;
		this.nAirNum = nAirNum;
		return this;
	}

	/** 是否为全局技能 */
	public isGlobal(): boolean {
		return this.skillRes.type == JXBtlST.Global;
	}

	/** 是否为被动技能 */
	public isPassive(): boolean {
		return this.skillRes.type == JXBtlST.Passive;
	}

	/**是否是主动技能 */
	public isInitiat(): boolean {
		return this.skillRes.type === JXBtlST.Initiat;
	}

	/** 是否为追击技能 */
	public isPursuit(): boolean {
		return this.skillRes.type == JXBtlST.Pursuit;
	}

	// 是否为反击技能 *
	public isBeatback(): boolean {
		return this.skillRes.type == JXBtlST.Beatback;
	}

	/** 释放技能 */
	public press(model: JXBtlAns_PressModel) {
		//获取技能目标集群
		let target = this.getTargets();
		if (target.length) {
			let ansSkillInfo: JXAnsSkillInfo = { skillId: this.skillId, insId: JXBtlMgr.ins.anlysis.insIdGentor.getNewId(), effects: [], model, execer: this.our.id, type: this.skillRes.type };
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_PRESS, this.our.id, ansSkillInfo);
			for (let i = 0; i < this.effects.length; i++) {
				this.effects[i].bindAtkTargets(target);
				let ansSkillEffect = this.effects[i].active();
				JXBtlMgr.ins.cleanWaitRemoveBuffs();
				if (ansSkillEffect) ansSkillInfo.effects.push(...ansSkillEffect);
			}
			JXBtlMgr.ins.anlysis.setSkillInfo(ansSkillInfo);
			JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_PRESS_END, this.our.id, model, ansSkillInfo.insId);
		}

	}

	/**获取判定目标 */
	public getTargets(): JXBattleEntity[] {
		if (this.nAirCamp === undefined) {
			return;
		}
		let candidates: JXBattleEntity[] = [];
		// 第一次筛选： 根据敌我判定
		this.emCondition(candidates);
		// 第二次筛选： 根据攻击范围判定
		this.spoceCondition(candidates);
		// 第三次筛选：根据目标类型
		this.airPosCondition(candidates);
		// 第四次筛选： 根据范围选择候选中的目标作为具体目标
		this.rangeCondition(candidates);
		//第五次筛选数量
		this.numCondition(candidates);
		this.isEndCondition(candidates);
		/**第六次筛选重新确认阵营*/
		this.emRecheck(candidates);
		return candidates;
	}

	/**敌我判定*/
	protected emCondition(candidates: JXBattleEntity[]) {
		let teamEntiy = this.our as JXBattleTeamEntiry;
		if (this.nAirCamp === JXBtlSAirCEM.All || this.nAirCamp == JXBtlSAirCEM.Enemy) {
			candidates.push(...teamEntiy.team.enemyTeam().getRoles(v => !v.isDie))
		}

		if (this.nAirCamp === JXBtlSAirCEM.All || this.nAirCamp == JXBtlSAirCEM.ME) {
			candidates.push(...teamEntiy.team.getRoles(v => !v.isDie));
		}
	}

	protected emRecheck(candidates: JXBattleEntity[]) {
		if (this.nAirCamp != JXBtlSAirCEM.All) {
			for (let i = candidates.length - 1; i >= 0; i--) {
				let role = candidates[i];
				let target = null;
				if (this.our.camp === JXBtlCamp.Defenser) {
					target = this.nAirCamp === JXBtlSAirCEM.Enemy ? JXBtlCamp.Attacker : JXBtlCamp.Defenser;
				} else {
					target = this.nAirCamp === JXBtlSAirCEM.Enemy ? JXBtlCamp.Defenser : JXBtlCamp.Attacker;
				}
				if (role.camp != target) JXBattleUtility.fastRemoveAt(candidates, i);
			}
		}
	}

	/**范围筛选 */
	protected spoceCondition(candidates: JXBattleEntity[]) {
		let teamEntiy = this.our as JXBattleTeamEntiry;
		let myRole = teamEntiy.jxRole;
		let myPos: cc.Vec2 = null;
		myPos = myRole.cmd.btlMapConverts.converToMapPos(myRole.birthPos);
		let adj = GameMgr.mapMgr.getAdjacent(teamEntiy.scopeId, myPos);
		adj.push(myPos);
		for (let i = candidates.length - 1; i >= 0; i--) {
			let role = candidates[i].jxRole;
			let rolePos = role.cmd.btlMapConverts.converToMapPos(role.birthPos);
			let isIn = false;
			for (let j = 0; j < adj.length; j++) {
				if (adj[j].x === rolePos.x && adj[j].y === rolePos.y) {
					isIn = true;
					/**规避对自身产生敌方效果*/
					if (this.our.id == candidates[i].id && this.nAirCamp === JXBtlSAirCEM.Enemy) {
						isIn = false;
					}
					break;
				}
			}
			if (!isIn) JXBattleUtility.fastRemoveAt(candidates, i);
		}
	}
	/**根据目标类型筛选 */
	protected airPosCondition(candidates: JXBattleEntity[]) {
		if (this.nAirType === INVALID_VALUE) return;
		for (let i = candidates.length - 1; i >= 0; i--) {
			switch (this.nAirType) {
				case JXBtlSAirT.Any: {
					let entity = candidates[MathEx.random(0, candidates.length - 1)];
					candidates = [entity]
					break;
				}
				case JXBtlSAirT.Every: {
					break;
				}
				case JXBtlSAirT.RDSelf: {
					if (candidates[i] != this.our) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Bing: {
					if (candidates[i].raceType != JXBtl_Race.SOLDIER) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Che: {
					if (candidates[i].raceType != JXBtl_Race.VEHICLE) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Ma: {
					if (candidates[i].raceType != JXBtl_Race.HORSE) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Xiang: {
					if (candidates[i].raceType != JXBtl_Race.MUTUALLY) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Pao: {
					if (candidates[i].raceType != JXBtl_Race.CANNON) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Shi: {
					if (candidates[i].raceType != JXBtl_Race.SCHOLAR) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.Bing: {
					if (candidates[i].raceType != JXBtl_Race.SOLDIER) JXBattleUtility.fastRemoveAt(candidates, i);
					break;
				}
				case JXBtlSAirT.LastAtk: {
					candidates.length = 0;
					if (!(this.our instanceof JXBattleTeamEntiry)) break;
					let role = this.our.lastComHurter;
					if (role && !role.isDie) {
						candidates.push(role);
					}
					break;
				}
				case JXBtlSAirT.LastAtkMe: {
					candidates.length = 0;
					if (!(this.our instanceof JXBattleTeamEntiry)) break;
					let role = this.our.lastAtker;
					if (role && !role.isDie && role.collision == JxBtlCollisionType.Normal) {
						candidates.push(role);
					}
					break;
				}

			}
		}
	}



	/**根据范围筛选 */
	protected rangeCondition(candidates: JXBattleEntity[]) {
		if (this.nAirRange == JXBtlSAirTR.Every || this.nAirRange === INVALID_VALUE) {
			return;
		}
		if (this.nAirRange == JXBtlSAirTR.RDMaxHpOne) {
			let airNum = 1;
			if (airNum >= candidates.length) {
				return;
			}
			candidates.sort((a, b) => b.curHp - a.curHp);
			candidates.splice(airNum, candidates.length - airNum);

		} else if (this.nAirRange == JXBtlSAirTR.RDMinHpOne) {
			let airNum = 1;
			if (airNum >= candidates.length) {
				return;
			}
			candidates.sort((a, b) => a.curHp - b.curHp);
			candidates.splice(airNum, candidates.length - airNum);
		}
	}

	/**根据数量进行筛选 */
	protected numCondition(candidates: JXBattleEntity[]) {
		if (this.nAirNum === INVALID_VALUE) {
			return
		}
		for (let i = candidates.length - 1; i >= 0; i--) {
			if (candidates.length > this.nAirNum) {
				JXBattleUtility.fastRemoveAt(candidates, i);
			}

		}
	}

	/**如果角色在行动中不作为目标 */
	protected isEndCondition(candidates: JXBattleEntity[]) {
		for (let i = candidates.length - 1; i >= 0; i--) {
			let role = candidates[i].jxRole;
			if (!role.checkRoleIsEnd()) JXBattleUtility.fastRemoveAt(candidates, i);
		}
	}


	/** 周期函数： 进入回合 */
	public onEnterSkill(nRound: number): boolean {
		/** 回合检测 -血量检测- 概率检测 */
		if (!this.roundCondition(nRound)) return false;
		if (!this.boolCondition(nRound)) return false
		if (!this.randomConditon()) return false;
		/** 如果是反击或者追击技能，则返回成功施法的标志位，并且插入一个衍生动作到队列中*/
		if (this.isPursuit() || this.isBeatback()) return true;
		this.press(JXBtlAns_PressModel.RoundPoll);
		return true;
	}


	/** 释放条件： 回合检测 */
	public roundCondition(nRound: number): boolean {
		let roundConfig: any = this.skillRes.condition[JXBtlPs.S.PCDT.Type];
		if (JXBattleUtility.isNumber(roundConfig)) {
			if (nRound == 0) return false;
			switch (roundConfig) {
				case JXBtlSRC.Every: return true;
				case JXBtlSRC.Singular: return nRound % 2 != 0;
				case JXBtlSRC.Even: return nRound % 2 == 0;
				/** 其他情况的回合判断都是不通过的 */
				default: return false;
			}
		}
		else {
			return roundConfig.indexOf(nRound) != JXBtlPs.Invalid;
		}
	}

	/**剩余血量判定 */
	public boolCondition(nRound: number): boolean {
		let config: number = this.skillRes.condition[JXBtlPs.S.PCDT.Surplus];
		if (nRound === 0) return false;
		if (config === INVALID_VALUE) return true;
		let curBool = this.our.curHp;
		let maxBool = this.our.maxHp;
		let boolPro = curBool / maxBool;
		if (boolPro <= config) {
			return true
		} else {
			return false;
		}
	}


	/** 释放概率检测 */
	public randomConditon(): boolean {
		let base = this.skillRes.condition[JXBtlPs.S.PCDT.Rate];
		let rd = JXBtlMgr.ins.random.getRandom();
		return rd <= base;
	}



}
/** 技能BUFF，实际效果 */
export class JXBattleBuff {
	/** BUFF唯一ID */
	public uuid: string;

	/** Effect静态配置 */
	public res: SSkillEffectRaw;

	/** 受到BUFF影响的对象 */
	public target: JXBattleEntity;
	/** BUFF来源的效果原型 */
	public effect: JXBattleEffect;
	/** BUFF生效的临时属性 */
	public propts: number | number[];
	/** BUFF的堆叠链路 */
	public storey: any;
	/** BUFF 组： 同步effect.groups */
	public groups: JXBattleBuff[];
	/** 效果组组长 */
	public groupsRoot: JXBattleBuff;

	/** 准备回合定时器 */
	public perpareTimer: JXRoundTimer = null;
	/** 生效回合定时器 */
	public lifeTimer: JXRoundTimer = null;
	/** 生效计数, 有部分BUFF是按照次数生效的 */
	protected _takeTimes: number = 0;
	/** 当前可生效最大次数 */
	protected _nMaxTakeTimes: number = 0;
	/** 作为群攻性BUFF的伤害提升次数判定的标志 */
	protected _totalDamageHurtTimesEnv: number = null;
	/** 作为群体治疗性BUFF的治疗提升次数判定标志 */
	protected _totalAddHpTimesEnv: number = null;
	/** 作为动态概率 */
	protected _runtimeRate: number = null;
	public get runtimeRate() { return this._runtimeRate; }
	/** 全局属性缓存 */
	protected _globalProptsCaches: Array<number | number[]>;

	/** 用来记录BUFF的信息 */
	public ansBuff: JXAnsBuffInfo;

	/** 状态标志：在回合开始的时候，会进行清除 */
	protected _stateFlag: number = 0;
	public get stateFlag(): number {
		return this._stateFlag;
	}

	/** 是否已经被标记销毁 */
	public get isDestroy(): boolean {
		return !!(this._stateFlag & BUFF_FLAG.DESTROY);
	}

	/** 本回合是否已经计算过效果 */
	public get isCalculatPropts(): boolean {
		return !!(this._stateFlag & BUFF_FLAG.CALCULAT);
	}

	/** 如果有限制回合只生效一次的情况 */
	public get isRoundEffect(): boolean {
		return !!(this._stateFlag & BUFF_FLAG.ROUND_EFFECT);
	}

	/** 重置回合生效标志，仅有在目标行动结束后会进行重置 */
	public resetRoundEffect() {
		this._stateFlag &= ~BUFF_FLAG.ROUND_EFFECT;
	}


	/** 本回合是否可以生效 */
	public get isCanActive(): boolean {
		return !!(this._stateFlag & BUFF_FLAG.ACTIVE) && !this.isDestroy && !this.isRoundEffect;
	}

	/** 是否为属性BUFF */
	public get isProptsBuff(): boolean {
		return this.res.effectMold == JXBtlBEM.SubPropts
			/** 降低属性（百分比） */
			|| this.res.effectMold == JXBtlBEM.SubMulPropts
			/** 提升属性（固定值） */
			|| this.res.effectMold == JXBtlBEM.AddPropts
			/** 提升属性（百分比） */
			|| this.res.effectMold == JXBtlBEM.AddMulPropts
			|| this.res.effectMold == JXBtlBEM.RoundActivePropts;
	}

	/** 是否有次数限制 */
	public get isTimesBuff(): boolean {
		return this._nMaxTakeTimes > 0;
	}

	/** 获取BUFF的优先级 */
	public get priority(): number {
		if (!this.effect) return null;
		return this.effect.priority;
	}

	constructor(effect: JXBattleEffect) {
		this.effect = effect;
		this.res = JXBattleCb.getEffectData(effect.nBufId);
		this.uuid = JXBattleUtility.BuffIdGtor.getNewId();
		this._takeTimes = 0;

		this.ansBuff = {
			insId: this.uuid,
			index: effect.nIndex,
			buffId: this.effect.nBufId,
			execer: this.effect.skill.our.id,
			effects: []
		} as any;
	}

	/** 设置目标， 如果可以添加到目标则返回自己，否则返回null */
	public bindTarget(role: JXBattleEntity): JXBattleBuff {
		this.ansBuff.target = role.id;
		JXBtlMgr.ins.anlysis.setBuffInfo(this.ansBuff);

		// 效果类型判定
		let againstType = JXBtlPs.Invalid;
		switch (this.res.effectType) {
			/** 照成伤害 */
			case JXBtlBEMT.Damage: againstType = JXBtlBEM.ImDamage; break;
			/** 造成治疗 */
			case JXBtlBEMT.AddHp: {
				let isProtect = JXBtlPs.B.PROTECTS.indexOf(this.res.effectMold) != JXBtlPs.Invalid;
				againstType = isProtect ? JXBtlBEM.BanProtect : JXBtlBEM.BanAddHp;
				break;
			}
			/** 减益 */
			case JXBtlBEMT.DeBuff: againstType = JXBtlBEM.ImDeBuff; break;
			/** 增益 */
			case JXBtlBEMT.Buff: againstType = JXBtlBEM.BanBuff; break;
			/** 控制 */
			case JXBtlBEMT.Ctrl: againstType = JXBtlBEM.ImDeCtrl; break;
			/** 免疫 */
			case JXBtlBEMT.Ime: againstType = JXBtlBEM.BanIme; break;
		}

		if (againstType != JXBtlPs.Invalid) {
			let banBuff = role.checkAndTakeBEM(againstType, this.priority);
			if (banBuff) {
				this.ansBuff.imBuffId = banBuff.uuid;
				JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_IMDE, role.id, JXBtlBEM.ImDeCtrl, this.effect.nBufId, banBuff.effect.nBufId);
				return;
			};
		}
		// 叠加判定
		let effectRp = this.buffRp();
		if (effectRp == JXBtlBER.Invalid) {
			if (role.hasEffectById(this.effect.nBufId)) {
				this.ansBuff.imBuffId = this.uuid;
				return;
			}

		}
		else if (effectRp == JXBtlBER.Cover) {
			let buffs = role.getEffectById(this.effect.nBufId);
			for (let i = buffs.length - 1; i >= 0; i--) {
				buffs[i].setDestroy();
			}
		}
		else if (effectRp >= JXBtlBER.OverlieMinNum && effectRp <= JXBtlBER.OverlieMaxNum) {
			let buffs = role.getEffectById(this.effect.nBufId);
			if (buffs.length >= effectRp) {
				this.ansBuff.imBuffId = this.uuid;
				return;
			}
		}
		this.target = role;
		this.target.addBuff(this);
		this.effect.skill.our.addControlBuff(this);
		return this;

	}

	/** 和目标解绑 */
	public unBindTarget() {
		if (!this.target) return;
		if (this.isProptsBuff) {
			this.target.flag |= JXBtlPs.R.FLAG.PROPTS;
		}
		this.target.removeBuff(this);
		this.effect.skill.our.removeControlBuff(this);
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_REMOVE_BUFF, this.effect.skill.our.id, this.uuid, this.effect.skill.skillId, this.effect.nBufId, this.target.id);
	}

	/** 绑定效果组 */
	public addInGroup(buff: JXBattleBuff) {
		if (!this.groups) this.groups = [];
		this.groups.push(buff);
		buff.groupsRoot = this;
	}

	/** 将自己从绑定组中移除 */
	public removeFromGroup() {
		if (this.groupsRoot) {
			JXBattleUtility.remove(this.groupsRoot.groups, this);
			this.groupsRoot = null;
		}
	}

	/** 获取BUFF的叠加模式 */
	public buffRp(): number {
		return JXBtlBER.Forever;
	}

	/** 事件函数。创建 */
	public onCreate() {
		// 全局技能，提前计算所有属性缓存
		if (this.effect.skill.isGlobal()) {
			this.calculatGlobalEffectCaches();
		}

		if (this.effect.nBufPrepare != 0) {
			this.startPerpare();
		}
		else {
			this.onEnterLife();
		}
	}

	/** 设置销毁标志 */
	public setDestroy() {
		if (this.isDestroy) return;
		this._stateFlag |= BUFF_FLAG.DESTROY;
		// 如果当前在锁血中，进标志移除
		if (this._stateFlag & BUFF_FLAG.LOCKHP_EFFECT) return;
		JXBtlMgr.ins.addRemoveBuff(this);
	}

	/** 生效计数器
	    * @param unActive 本回合是否不再生效
	    */
	public take(unActive: boolean = false) {
		this._takeTimes++;
		if (unActive) {
			this._stateFlag |= BUFF_FLAG.ROUND_EFFECT;
		}
		if (this.maxTakeTimes() == 0) return;
		if (this._takeTimes >= this.maxTakeTimes()) {
			this.setDestroy();
		}
	}

	public startLockHp() {
		this._stateFlag |= BUFF_FLAG.LOCKHP_EFFECT;
	}

	public endLockHp() {
		this._stateFlag &= ~BUFF_FLAG.LOCKHP_EFFECT;
		if (this.isDestroy) {
			this.setDestroy();
		}
	}

	/** 事件函数：销毁 */
	public destroy() {
		if (this.groups) for (let i = this.groups.length - 1; i >= 0; i--) {
			this.groups[i].removeFromGroup();
		}
		this.groups = null;
		this.removeFromGroup();
		this.unBindTarget();
		this.perpareTimer && this.perpareTimer.destroy();
		this.lifeTimer && this.lifeTimer.destroy();
		this.perpareTimer = null;
		this.lifeTimer = null;
		this._globalProptsCaches = null;
	}

	/** 最大生效次数 */
	protected maxTakeTimes(): number {
		return this._nMaxTakeTimes as number;
	}


	/** 开始准备 */
	public startPerpare(): JXBattleBuff {
		let nnBufPrepare = this.effect.nBufPrepare;
		this.perpareTimer = new JXRoundTimer(nnBufPrepare, this.onPerpared.bind(this));
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_PREPARE_BUFF, this.effect.skill.our.id, this.uuid, nnBufPrepare);
		this.ansBuff.prepareRd = nnBufPrepare;
		return this;
	}


	/** 事件函数： 准备完成 */
	protected onPerpared() {
		this.perpareTimer.destroy();
		this.perpareTimer = null;
		// 生效。
		this.onEnterLife();
	}

	/** 开始生效 */
	protected onEnterLife() {
		let isDuration = this.effect.nBufDuration != 0;
		// 立即生效类型的BUFF
		if (!isDuration) {
			this.calculatEffect();
			this.active();
			this.setDestroy();
			return;
		}

		let nBufDuration = this.effect.nBufDuration;
		JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_ADD_BUFF, this.target.id, this.uuid, this.effect.skill.skillId, this.effect.nBufId, this.effect.skill.our.id, this.target.id);
		this.lifeTimer = new JXRoundTimer(nBufDuration, this.onEndLife.bind(this));
		this.ansBuff.lifeRd = nBufDuration;

		/** 第一回合就需要进行生效判定 */
		this.curRoundLifeCheck();
		if (!this.isCanActive) return;
		this.calculatEffect();
		if (this.res.effectType == JXBtlBEMT.Buff || this.res.effectType == JXBtlBEMT.DeBuff || this.res.effectType == JXBtlBEMT.Ctrl || this.res.effectType == JXBtlBEMT.AddHp || this.res.effectType == JXBtlBEMT.AddFp) {
			this.active();
		}
	}

	/** 时间函数： 回合结束 */
	public onControlRoundBegin() {
		this._stateFlag &= ~(BUFF_FLAG.ACTIVE | BUFF_FLAG.CALCULAT);
		if (this.isDestroy) return;
		//准备判定
		if (this.perpareTimer) {
			this.perpareTimer.life();
			return;
		}
		// 持续判定
		if (this.lifeTimer) {
			this.lifeTimer.life();
		}
		if (this.isDestroy) return;
		// 中断判定
		this.curRoundBreakCheck();
		this.curRoundLifeCheck();

		/** 计算一下属性 */
		this.calculatEffect();

		// 如果是属性BUFF,则需要立即计算需要生效的属性
		if (this.isCanActive && (this.res.effectType == JXBtlBEMT.Buff || this.res.effectType == JXBtlBEMT.DeBuff)) {
			this.active();
		}
	}

	/** 事件函数： 本回合是否生效判定 */
	public curRoundLifeCheck() {
		if (this.groupsRoot && !this.groupsRoot.isDestroy && this.effect.continues.length == 0) {
			let isActive = this._stateFlag & BUFF_FLAG.ACTIVE;
			if (isActive) {
				this._stateFlag |= BUFF_FLAG.ACTIVE;
			}
			else {
				this._stateFlag &= ~BUFF_FLAG.ACTIVE;
			}
			return;
		}
		if (this.effect.continues.length == 0 || this.effect.continues[JXBtlArrIx.Zero] >= JXBtlMgr.ins.random.getRandom()) {
			this._stateFlag |= BUFF_FLAG.ACTIVE;
		}
		else {
			this._stateFlag &= ~BUFF_FLAG.ACTIVE;
		}
	}

	/** 事件函数： 激活（一种是立即生效，一种是到对方行动的时候生效） */
	public active() {
		if (this.target.isDie) return;
		// 如果有需要返回数据
		let outAns: JxAnsInfo;
		switch (this.res.effectMold) {
			case JXBtlBEM.Hurt: {
				// 受击者受击 -》攻击者吸血 -》受击者被动检测(受击者反伤-》受击者受击技能判定)
				if (this.target.collision != JxBtlCollisionType.Normal) break;
				let ansHurtInfo = this.target.onSkillHurt(this);
				this.effect.skill.our.onAtkingEvent(this.target, ansHurtInfo, this);
				this.target.onHurtingEvent(this.effect.skill.our, ansHurtInfo, this);
				outAns = ansHurtInfo;
				break;
			}
			case JXBtlBEM.AddHp: {
				/** 禁止治疗 */
				if (this.target.collision != JxBtlCollisionType.Normal) break;
				let isBanAddHp = this.target.checkAndTakeBEM(JXBtlBEM.BanAddHp, this.priority);
				if (isBanAddHp) break;
				outAns = this.target.onSkillAddHp(this);
				break;
			}
			case JXBtlBEM.AddProtect: {
				let isBanAddProtect = this.target.checkAndTakeBEM(JXBtlBEM.BanProtect, this.priority);
				if (isBanAddProtect) break;
				outAns = this.target.onSkillAddHp(this);
				break;
			}
			case JXBtlBEM.ClDamage: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.Damage);
				break;
			}
			case JXBtlBEM.ClDeBuff: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.DeBuff);
				break;
			}
			case JXBtlBEM.ClCtl: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.Ctrl);
				break;
			}
			case JXBtlBEM.ClAddHp: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.AddHp);
				break;
			}
			case JXBtlBEM.ClBuff: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.Buff);
				break;
			}
			case JXBtlBEM.ClIm: {
				this.target.clearBuffsByEffectType(this, JXBtlBEMT.Ime);
				break;
			}
			case JXBtlBEM.ClByBuffId: {
				this.target.clearBuffsByEffectId(this);
				break;
			}

			case JXBtlBEM.BanSkill: {
				// 检测技能是否打断
				for (let i = 0; i < this.target.skills.length; i++) {
					// 技能不在准备中
					if (this.target.skills[i].priority < this.priority) continue;
					this.take();
				}
				break;
			}

			case JXBtlBEM.AddMaxHp: {
				if (this.target.collision != JxBtlCollisionType.Normal) break;
				outAns = this.target.onSkillAddMaxHp(this);
				break;
			}
			/** 降低属性 */
			case JXBtlBEM.SubPropts:
			/** 降低属性（百分比） */
			case JXBtlBEM.SubMulPropts:
			/** 提升属性（固定值） */
			case JXBtlBEM.AddPropts:
			/** 提升属性（百分比） */
			case JXBtlBEM.AddMulPropts:
			case JXBtlBEM.RoundActivePropts:
				{
					this.ansBuff.effects.push(this.propts);
					if (this.propts[JXBtlPs.R.PORPTS.PROTECT]) {
						let addProtect = this.target.onAddHp(Math.floor(this.propts[JXBtlPs.R.PORPTS.PROTECT]), true);
						let ansAddHp: JXAnsAddHpInfo = {
							insId: null,
							execer: this.effect.skill.our.id,
							target: this.target.id,
							isCrit: false,
							addNum: addProtect,
							isProtect: true,
							insBuff: this.uuid
						}
						JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_SKILL_ADDHP, this.target.id, ansAddHp);
					}

					// 带次数的属性加成将不进行统一计算。不同属性将在生效的时候计算
					if (this._nMaxTakeTimes > 0) {
						this.target.checkIsTimesPropts();
						break;
					};
					this.target.flag |= JXBtlPs.R.FLAG.PROPTS;
					break;
				}
			case JXBtlBEM.RELife: {
				if (this.target.isDie) {
					this.target.flag &= ~JXBtlPs.R.FLAG.DIE;
					let reHp = Math.floor(this.target.getPropts(PART_PROPTS.FormulaMaxHp) * (this.propts as number));
					this.target.onAddHp(reHp);
					JXBtlMgr.ins.onEvent(JXBattleEvt.ROLE_RELIFE, this.target.id, this.uuid, this.target.id, reHp);
				}
				break;
			}
			case JXBtlBEM.ExEffect: {
				let [nBuffId, nAddLife] = this.propts as number[];
				let buffs = this.target.getEffectById(nBuffId);
				let uuids = [];
				for (let i = 0; i < buffs.length; i++) {
					if (buffs[i].isDestroy) continue;
					if (!buffs[i].lifeTimer) continue;
					if (buffs[i].effect.skill.isGlobal()) continue;
					buffs[i].lifeTimer.addTotalTimes(nAddLife);
					uuids.push(buffs[i].uuid);
				}
				this.ansBuff.effects.push(...uuids);
				JXBtlMgr.ins.onEvent(JXBattleEvt.LIFE_TIME_CHANGE, this.target.id, this.uuid, uuids, nAddLife);
				break;
			}
			case JXBtlBEM.Detonated: {
				let [nBuffId, nCount] = this.propts as number[];
				let buffs = this.target.getEffectById(nBuffId);
				let effects = [];
				for (let i = 0, l = Math.min(nCount, buffs.length); i < l; i++) {
					if (this.effect.skill.our.isDie) break;
					if (this.target.isDie) break;
					let buff = buffs[i];
					if (buff.isDestroy) continue;
					// if (!buff.lifeTimer) continue;
					this._stateFlag |= BUFF_FLAG.CALCULAT;
					buff.calculatEffect();
					let ans: JxAnsInfo = buff.active();
					effects.push({ uuid: buff.uuid, effect: ans ? ans.insId : null });
				}
				this.ansBuff.effects.push(...effects);
				JXBtlMgr.ins.onEvent(JXBattleEvt.DETONATED_BUFF, this.target.id, this.uuid, effects);
				break;
			}

			/** 其他的类型的效果为被动效果 */
			default: break;
		}
		return outAns;

	}

	/** 事件函数： 是否中断判定 */
	public curRoundBreakCheck() {
		if (this.groupsRoot && this.effect.continues.length == 0) {
			let isParentBreak = (this.groupsRoot._stateFlag & BUFF_FLAG.BREAK);
			if (isParentBreak) {
				this._stateFlag |= BUFF_FLAG.BREAK;
				this.setDestroy();
			}
			return;
		}
		if (this.effect.continues.length == 0 || this.effect.continues[JXBtlArrIx.One] > JXBtlMgr.ins.random.getRandom()) {
			this._stateFlag |= BUFF_FLAG.BREAK;
			this.setDestroy();
		}
	}


	/** 结束生命周期 */
	protected onEndLife() {
		this.lifeTimer.destroy();
		this.lifeTimer = null;
		this.setDestroy();
	}

	/** 计算效果输出 */
	private calculatEffect(nRound?: number) {
		if (this._stateFlag & BUFF_FLAG.CALCULAT) return;
		this._stateFlag |= BUFF_FLAG.CALCULAT;
		if (this.effect.skill.isGlobal()) {
			let nLife = this.lifeTimer ? this.lifeTimer.nLife : 0;
			this.propts = this._globalProptsCaches[nLife];
			return;
		}
		let index = this.effect.affect[JXBtlArrIx.Zero];
		if (!index) return;
		let func = this['effectFormula_' + index];
		if (!func) return;
		func.call(this, nRound);
	}

	/** 计算全局技能的属性缓存 */
	public calculatGlobalEffectCaches() {
		this._globalProptsCaches = [];
		let len = this.effect.nBufDuration ? this.effect.nBufDuration : 1;
		for (let i = 0; i < len; i++) {
			this.propts = null;
			let index = this.effect.affect[JXBtlArrIx.Zero];
			if (!index) return;
			let func = this['effectFormula_' + index];
			if (!func) return;
			func.call(this, i);
			this._globalProptsCaches.push(this.propts);
		}
	}

	/** 成长计算 */
	private affectValue(nRound?: number): number[] {
		let ret = [];
		let decay = this.effect.decay || 0;
		let nLife = nRound != null ? nRound : (this.lifeTimer ? this.lifeTimer.nLife : 0);
		for (let i = JXBtlArrIx.One; i < this.effect.affect.length; i++) {
			ret[i] = this.effect.affect[i] * (1 + decay * nLife);
		}
		return ret;
	}


	//通用
	/** 效果计算公式1 造成伤害&&造成治疗=*a（常用）*/
	/**[101,2] */
	private effectFormula_1(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		let [atk, isCrit] = this.effect.skill.our.calculatDamge(this.target);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = atk * a;
	}

	/**
	 *效果计算公式2 治疗&&护盾= 我方攻击*系数
	 * @param nRound 
	 */
	private effectFormula_2(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		this.propts = this.target.getPropts(PART_PROPTS.GongJi) * a
	}

	/** 效果计算公式3 a为属性编号，代表该属性提升b值（可为负）*/
	private effectFormula_3(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = b;
	}

	/** 效果计算公式4 a为属性编号，代表该属性提升属性*b值（既百分比提升，可为负）*/
	private effectFormula_4(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = this.target.getBasePropts(a) * b;
	}

	/** 效果计算公式5 属性提升：目标攻击提升a,目标防御提升b……(攻击,防御,生命,能量，暴击，闪避，爆伤)*/
	private effectFormula_5(nRound?: number) {
		const PARPTS = [JXBtlPs.Invalid, PART_PROPTS.GongJi, PART_PROPTS.FangYu, PART_PROPTS.XueLiang, PART_PROPTS.BaoJi, PART_PROPTS.ShanBi, PART_PROPTS.BaoShang];
		let totalAffect = this.affectValue(nRound);
		this.propts = [];
		for (let i = JXBtlArrIx.One; i < PARPTS.length; i++) {
			this.propts[PARPTS[i]] = totalAffect[i];
		}
	}

	/** 效果计算公式6 属性提升：目标攻击提升攻击*a,目标防御提升防御*b……*/
	private effectFormula_6(nRound?: number) {
		const PARPTS = [JXBtlPs.Invalid, PART_PROPTS.GongJi, PART_PROPTS.FangYu, PART_PROPTS.XueLiang, PART_PROPTS.BaoJi, PART_PROPTS.ShanBi, PART_PROPTS.BaoShang];
		let totalAffect = this.affectValue(nRound);
		this.propts = [];
		for (let i = JXBtlArrIx.One; i < PARPTS.length; i++) {
			this.propts[PARPTS[i]] = this.target.getBasePropts(PARPTS[i]) * totalAffect[i];
		}
	}


	/** a为属性编号，代表该属性提升b值（既固定值提升，可为负），该效果只作用c次 */
	private effectFormula_7(nRound?: number) {
		let [_, a, b, c] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = b;
		this._nMaxTakeTimes = c;
	}

	/** a为属性编号，代表该属性提升属性*b值（既百分比提升，可为负），该效果只作用c次 */
	private effectFormula_8(nRound?: number) {
		let [_, a, b, c] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = this.target.getPropts(a) * b;
		this._nMaxTakeTimes = c;
	}

	/** a为属性编号，代表该属性提升编号为b的属性值*c值（既百分比提升，可为负） */
	private effectFormula_9(nRound?: number) {
		let [_, a, b, c] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = this.target.getPropts(b) * c;
	}

	/** a为属性编号，代表该属性提升((编号为b的属性值-编号为c的属性值)/d值[除完向下取整])*e值（既百分比提升，可为负） */
	private effectFormula_10(nRound?: number) {
		let [_, a, b, c, d, e] = this.affectValue(nRound);
		this.propts = [];
		this.propts[a] = Math.floor((this.target.getPropts(b) - this.target.getPropts(c)) / (d * 1.0)) * e;
	}


	/** 效果计算公式11 a为立即生效数量（清除&引爆N个效果） */
	private effectFormula_11(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		this.propts = a;
	}

	/** 效果计算公式12 a为持续效果生效的最大次数（持续类效果可生效的最大次数，0为无限） */
	private effectFormula_12(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		this._nMaxTakeTimes = a;
	}

	/** 效果计算公式13 a为指定效果ID，b为延长回合数 */
	private effectFormula_13(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		this.propts = [a, b];
	}

	/** a为指定效果ID （b持续类效果可生效的最大次数，0为无限）*/
	private effectFormula_14(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		this.propts = a;
		this._nMaxTakeTimes = b;
	}


	/** a为锁血生效次数，锁血后下一次行动恢复编号为b的属性值*c值的生命 */
	private effectFormula_15(nRound?: number) {
		let [_, a, b, c] = this.affectValue(nRound);
		this._nMaxTakeTimes = a;
		let our = this.effect.skill.our;
		this.propts = our.getPropts(b) * c;
	}

	/** a为锁血生效次数，锁血后下一次行动治疗=普攻*b */
	private effectFormula_16(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		this._nMaxTakeTimes = a;
		let our = this.effect.skill.our;
		let [hurt, isCrit] = our.calculatDamge(this.target);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = hurt * b;
	}



	// 造成伤害
	/**
	  * 伤害= 穿透伤害 * a
	  */
	/**[102,2] */
	private effectFormula_101(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		let [atk, isCrit] = this.effect.skill.our.calculatDamge(this.target, JXBtlPs.C.CT);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = atk * a;
	}


	/**
	  * 斩击伤害=穿透伤害*a+（（b*目标最大血量）/目标当前血量[除完向下取整]）*目标最大血量
	  * [103,0.8,]
	  */
	private effectFormula_102(nRound?: number) {
		let [_, a, b] = this.affectValue(nRound);
		let [atk, isCrit] = this.effect.skill.our.calculatDamge(this.target, JXBtlPs.C.CT);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = atk * a + (Math.floor(b * this.target.getPropts(PART_PROPTS.FormulaMaxHp) / this.target.curHp) * this.target.getPropts(PART_PROPTS.FormulaMaxHp));
	}

	/**
	 * 真实伤害(无视敌方闪避) = 普攻伤害 * a 
	 * [104,0.5]
	 */
	private effectFormula_103(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		let [atk, isCrit] = this.effect.skill.our.calculatDamge(this.target, JXBtlPs.C.BZ);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = atk * a;
	}

	/**普攻伤害2 =普攻=（攻击-防御）、（火强-火抗）、（冰强-冰抗）【三者取最大值】（*暴伤系数），判断是否闪避。 * a  */
	private effectFormula_104(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		let [atk, isCrit] = this.effect.skill.our.calculatDamge(this.target, JXBtlPs.C.WS2);
		isCrit ? (this._stateFlag |= BUFF_FLAG.CRIT) : (this._stateFlag &= ~BUFF_FLAG.CRIT);
		this.propts = atk * a;
	}

	/**治疗 */
	/**直接提升目标对应数值血量 */
	private effectFormula_201(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		this.propts = a;
	}

	/**治疗=目标最大血量*a */
	private effectFormula_202(nRound?: number) {
		let [_, a] = this.affectValue(nRound);
		this.propts = this.target.getPropts(PART_PROPTS.FormulaMaxHp) * a;
	}


	/**追加 */
	/** 效果计算公式301 a为吸血&吸盾&反伤系数，b为生效最大次数（0为无限） */
	private effectFormula_301(nRound?: number) {
		let [_, a, b, c] = this.affectValue(nRound);
		this._runtimeRate = a;
		this.propts = b;
		this._nMaxTakeTimes = c;
	}

	/**反馈 */
	/**  受伤时，有a的概率获得编号为b的自身属性*c的治疗&护盾，最多触发d次（0为无限）*/
	private effectFormula_302(nRound?: number) {
		let [_, a, b, c, d] = this.affectValue(nRound);
		this._runtimeRate = a;
		this.propts = [b, c];
		this._nMaxTakeTimes = d;
	}
}